package com.openlogic.common.plugins.db.api.utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.JsonNode;
import com.openlogic.common.plugins.db.api.datasource.DataSourceProcessor;
import com.openlogic.common.plugins.db.api.dto.BaseDataSourceColumnDto;
import com.openlogic.common.plugins.db.api.dto.BaseDataSourceParamDto;
import com.openlogic.common.plugins.db.api.dto.BaseDataSourceTableDto;
import com.openlogic.common.plugins.db.api.plugin.DataSourceProcessorProvider;
import com.openlogic.common.plugins.spi.enums.DbType;
import com.openlogic.datasource.api.entity.DataSourceEntity;
import com.openlogic.datasource.api.param.ConnectionParam;

import jodd.db.connection.ConnectionProvider;
import jodd.db.oom.DbOomQuery;

/**
* @ClassName: DataSourceUtils
* @Description: 数据源操作工具类
* @author weiyongpeng
* @date 2024年11月17日 下午1:43:45
 */
public class DataSourceUtils {
	
	private static final Logger log = LoggerFactory.getLogger(DataSourceUtils.class);
	
	public DataSourceUtils() {
    }

    /**
    * 描述：检查连接参数合法性
    * @Title: checkDatasourceParam
    * @param baseDataSourceParamDTO
    * @author weiyongpeng
    * @date  2024年11月17日 下午1:43:26
     */
    public static void checkDatasourceParam(BaseDataSourceParamDto baseDataSourceParamDTO) {
        getDatasourceProcessor(baseDataSourceParamDTO.getType()).checkDatasourceParam(baseDataSourceParamDTO);
    }

    /**
    * 描述：获取数据源JDBC连接字串
    * @Title: getJdbcUrl
    * @param dbType
    * @param baseConnectionParam
    * @return
    * @author weiyongpeng
    * @date  2024年11月17日 下午1:43:01
     */
    public static String getJdbcUrl(DbType dbType, ConnectionParam baseConnectionParam) {
        return getDatasourceProcessor(dbType).getJdbcUrl(baseConnectionParam);
    }

    /**
    * 描述：构建数据源连接参数实体对象
    * @Title: buildConnectionParams
    * @param baseDataSourceParamDTO
    * @return
    * @author weiyongpeng
    * @date  2024年11月17日 下午1:42:37
     */
    public static ConnectionParam buildConnectionParams(BaseDataSourceParamDto baseDataSourceParamDTO) {
        ConnectionParam connectionParams = getDatasourceProcessor(baseDataSourceParamDTO.getType())
                .createConnectionParams(baseDataSourceParamDTO);
        log.info("parameters map:{}", connectionParams);
        return connectionParams;
    }
    
    /**
    * 描述 获取数据源表元数据
    * @Title: getTables
    * @param dbType
    * @param dataBaseName
    * @param connectionParam
    * @return
    * @author weiyongpeng
    * @date  2024年11月22日 下午2:24:33
     */
    public static List<BaseDataSourceTableDto> getTables(DataSourceEntity dataSourceEntity){
    	DataSourceProcessor datasourceProcessor = getDatasourceProcessor(DbType.getDbType(dataSourceEntity.getDbType()));
    	ConnectionProvider createDataSource = datasourceProcessor.createDataSource(dataSourceEntity.getConnectionParams());
		List<BaseDataSourceTableDto> list = DbOomQuery.query(createDataSource.getConnection(), datasourceProcessor.tables(dataSourceEntity.getConnectionParams().getDatabase())).list(BaseDataSourceTableDto.class);
    	return list;
    }
    
    /**
    * 描述：获取数据源列元数据
    * @Title: getColumns
    * @param dbType
    * @param database
    * @param connectionParams
    * @return
    * @author weiyongpeng
    * @date  2024年11月22日 下午2:24:58
     */
	public static List<BaseDataSourceColumnDto> getColumns(DataSourceEntity dataSourceEntity, String tableName) {
		DataSourceProcessor datasourceProcessor = getDatasourceProcessor(DbType.getDbType(dataSourceEntity.getDbType()));
		ConnectionProvider createDataSource = datasourceProcessor.createDataSource(dataSourceEntity.getConnectionParams());
		List<BaseDataSourceColumnDto> list = DbOomQuery.query(createDataSource.getConnection(), datasourceProcessor.columns(dataSourceEntity.getConnectionParams().getDatabase() ,tableName)).list(BaseDataSourceColumnDto.class);
    	return list;
	}
    
    /**
    * 描述：获取数据源连接
    * @Title: getConnection
    * @param dbType
    * @param connectionParam
    * @return
    * @author weiyongpeng
    * @date  2024年11月17日 下午1:42:18
     */
    public static Connection getConnection(DbType dbType, ConnectionParam connectionParam) {
        try {
            return getDatasourceProcessor(dbType).getConnection(connectionParam);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
    * 描述：获取数据源表元信息
    * @Title: getTableColumnMeta
    * @param dbType
    * @param connectionParam
    * @param columnNamePattern
    * @return
    * @author weiyongpeng
    * @date  2024年11月28日 下午2:17:52
     */
    public static List<Map<String, String>> getTableColumnMeta(DbType dbType, ConnectionParam connectionParam, String tableName) {
        try {
        	List<Map<String, String>> arrayList = new ArrayList<>();
            Connection connection = getDatasourceProcessor(dbType).getConnection(connectionParam);
            ResultSet columns = connection.getMetaData().getColumns(connection.getCatalog(), connectionParam.getDatabase(), tableName, null);
            while(columns.next()){
            	Map<String, String> map = new HashMap<>();
                String colName = columns.getString("COLUMN_NAME");
                String remarks = columns.getString("REMARKS");
                map.put("key", colName);
                map.put("name", remarks);
                arrayList.add(map);
			}
            return arrayList;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
    * 描述：获取JDBCTemplate模板
    * @Title: getJdbcTemplate
    * @param dbType
    * @param connectionParam
    * @return
    * @author weiyongpeng
    * @date  2024年11月24日 下午4:30:20
     */
    public static ConnectionProvider getJdbcTemplate(DbType dbType, ConnectionParam connectionParam) {
		DataSourceProcessor datasourceProcessor = getDatasourceProcessor(dbType);
		ConnectionProvider createDataSource = datasourceProcessor.createDataSource(connectionParam);
    	return createDataSource;
	}

    /**
    * 描述：校验数据源连接
    * @Title: validConnection
    * @param dbType
    * @param connectionParam
    * @return
    * @author weiyongpeng
    * @date  2024年11月17日 下午1:41:52
     */
    public static Boolean validConnection(DbType dbType, ConnectionParam connectionParam) {
        try {
            return getDatasourceProcessor(dbType).getConnection(connectionParam).isValid(0);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
    * 描述：构建数据源参数实体根据前端传递的json串
    * @Title: buildDatasourceParam
    * @param param
    * @return
    * @author weiyongpeng
    * @date  2024年11月17日 下午1:41:08
     */
    public static BaseDataSourceParamDto buildDatasourceParam(String param) {
        JsonNode jsonNodes = JSONUtils.parseObject(param);
        return getDatasourceProcessor(DbType.ofName(jsonNodes.get("type").asText().toUpperCase()))
                .castDatasourceParamDTO(param);
    }
    
    /**
    * 描述：获取数据源唯一缓存ID
    * @Title: getDatasourceUniqueId
    * @param connectionParam
    * @param dbType
    * @return
    * @author weiyongpeng
    * @date  2024年11月17日 下午1:40:46
     */
    public static String getDatasourceUniqueId(ConnectionParam connectionParam, DbType dbType) {
        return getDatasourceProcessor(dbType).getDatasourceUniqueId(connectionParam, dbType);
    }
    
    /**
    * 描述：获取数据源连接驱动串
    * @Title: getDatasourceDriver
    * @param dbType
    * @return
    * @author weiyongpeng
    * @date  2024年11月17日 下午1:40:19
     */
    public static String getDatasourceDriver(DbType dbType) {
        return getDatasourceProcessor(dbType).getDatasourceDriver();
    }

    /**
    * 描述：根据数据源Type获取对应数据源处理器
    * @Title: getDatasourceProcessor
    * @param dbType
    * @return
    * @author weiyongpeng
    * @date  2024年11月17日 下午1:39:47
     */
    public static DataSourceProcessor getDatasourceProcessor(DbType dbType) {
        Map<String, DataSourceProcessor> dataSourceProcessorMap =
                DataSourceProcessorProvider.getDataSourceProcessorMap();
        if (!dataSourceProcessorMap.containsKey(dbType.name())) {
        	log.error("illegal datasource type {}");
            throw new IllegalArgumentException("illegal datasource type");
        }
        return dataSourceProcessorMap.get(dbType.name());
    }
    
    /**
    * 描述：获取所有数据源插件类型
    * @Title: getDatasourceTypes
    * @return
    * @author weiyongpeng
    * @date  2024年11月17日 下午1:39:13
     */
    public static Set<String> getDatasourceTypes() {
        Set<String> dataSourceAllType = DataSourceProcessorProvider.getDataSourceAllType();
        return dataSourceAllType;
    }

    /**
    * 描述：获取分页SQL
    * @Title: generatePageSql
    * @param dbType
    * @param orignSql
    * @param pageSize 
    * @param page 
    * @return
    * @author weiyongpeng
    * @date  2024年11月24日 下午5:05:25
     */
	public static String generatePageSql(DbType dbType, String orignSql, Integer page, Integer pageSize) {
		DataSourceProcessor datasourceProcessor = getDatasourceProcessor(dbType);
		String pageSql = datasourceProcessor.parsePageSql(orignSql,page,pageSize);
		return pageSql;
	}

	/**
	* 描述：获取count的SQL
	* @Title: generateCountSql
	* @param dbType
	* @param tableName
	* @author weiyongpeng
	* @return 
	* @date  2024年11月24日 下午5:05:48
	 */
	public static String generateCountSql(DbType dbType, String tableName) {
		DataSourceProcessor datasourceProcessor = getDatasourceProcessor(dbType);
		String countSql = datasourceProcessor.parseCountSql(tableName);
		return countSql;
	}

}
